#include <memory>
#include <iostream>
#include <brpc/server.h>
#include <butil/logging.h>
#include <unordered_set>

// es数据管理
#include "data_es.hpp"
// mysql数据管理
#include "mysql_chat_session.hpp"
#include "mysql_chat_session_member.hpp"
#include "mysql_apply.hpp"
#include "mysql_relation.hpp"

// etcd服务注册模块
#include "etcder.hpp"
#include "uuid.hpp"
#include "channel.hpp"
#include "logger.hpp"

// proto框架代码
#include "friend.pb.h"
#include "base.pb.h"
#include "user.pb.h"
#include "message.pb.h"

namespace bite_im
{
    // 实现用户模块功能

    // 用户模块服务类
    class FriendServiceImpl : public bite_im::FriendService
    {
    public:
        using ptr = std::shared_ptr<FriendServiceImpl>;
        FriendServiceImpl(const ElasticPtr &es_client,
                          const DBPtr &mysql_client,
                          const ServiceManager::ptr &service_manager,
                          const std::string &user_service_name,
                          const std::string &message_service_name)
            : _es_user(std::make_shared<ESUser>(es_client)),
              _mysql_apply(std::make_shared<FriendApplyTable>(mysql_client)),
              _mysql_relation(std::make_shared<RelationTable>(mysql_client)),
              _mysql_session(std::make_shared<ChatSessionTable>(mysql_client)),
              _mysql_session_member(std::make_shared<ChatSessionMemberTable>(mysql_client)),
              _service_manager(service_manager),
              _user_service_name(user_service_name),
              _message_service_name(message_service_name) {}

        ~FriendServiceImpl() {}

        /* --------------------------------------------- 业务函数----------------------------------------------------*/

        void GetFriendList(google::protobuf::RpcController *controller,
                           const ::bite_im::GetFriendListReq *request,
                           ::bite_im::GetFriendListRsp *response,
                           ::google::protobuf::Closure *done)
        {
            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);
            // 1.提取请求的用户id
            std::string user_id = request->user_id();
            // 2.通过数据库句柄获取好友id列表
            auto friend_id_vector = _mysql_relation->friends(user_id);
            // 将vector转为set符合GetUserInfo的参数列表
            std::unordered_set<std::string> friend_id_list;
            for (const auto &friend_id : friend_id_vector)
            {
                friend_id_list.insert(friend_id);
            }
            // 3.通过用户子服务批量获取好友的用户信息
            if (friend_id_list.size() != 0)
            {
                std::unordered_map<std::string, UserInfo> info_map;
                bool ret = GetUserInfo(request->request_id(), friend_id_list, info_map);
                if (ret == false)
                {
                    LOG_ERROR("调用用户子服务失败");
                    return err_response_func(request->request_id(), "调用用户子服务失败");
                }
                // 组织响应
                for (const auto &info_it : info_map)
                {
                    // info.second对应着UserInfo对象
                    auto user_info = response->add_friend_list();
                    user_info->CopyFrom(info_it.second);
                }
            }

            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void FriendRemove(google::protobuf::RpcController *controller,
                          const ::bite_im::FriendRemoveReq *request,
                          ::bite_im::FriendRemoveRsp *response,
                          ::google::protobuf::Closure *done)
        {
            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                // 无法登陆不用设置保存session_id
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);

            // 1.读取当前对象id和删除的好友id
            std::string user_id = request->user_id();
            std::string peer_id = request->peer_id();
            // 2.通过数据库句柄删除好友关系
            bool ret = _mysql_relation->remove(user_id, peer_id);
            if (ret == false)
            {
                LOG_ERROR("删除好友关系[{}]-[{}]失败", user_id, peer_id);
                return err_response_func(request->request_id(), "删除好友关系失败");
            }
            // 3.通过数据库句柄来删除单聊会话
            ret = _mysql_session->remove(user_id, peer_id);
            if (ret == false)
            {
                LOG_ERROR("删除好友[{}]-[{}]单聊会话失败", user_id, peer_id);
                return err_response_func(request->request_id(), "删除好友单聊会话失败");
            }
            // 是否要删除好友申请记录？
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void FriendAdd(google::protobuf::RpcController *controller,
                       const ::bite_im::FriendAddReq *request,
                       ::bite_im::FriendAddRsp *response,
                       ::google::protobuf::Closure *done)
        {
            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                // 无法登陆不用设置保存code_id
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);
            // 1.获取申请人和被申请人的信息---单纯发出请求不关心结果
            std::string user_id = request->user_id();
            std::string peer_id = request->respondent_id();

            std::string event_id = UUID::uuid();
            // 2.通过数据库句柄来判断两人是否已经是好友
            bool ret = _mysql_relation->exist(user_id, peer_id);
            if (ret == true)
            {
                LOG_ERROR("[{}]-[{}]已存在好友关系，无法重复申请", user_id, peer_id);
                return err_response_func(request->request_id(), "已存在好友关系，无法重复申请");
            }
            // 3.通过数据库句柄来判断当前是否已经申请过好友
            ret = _mysql_apply->exist(user_id, peer_id);
            if (ret == true)
            {
                LOG_ERROR("[{}]向[{}]申请过好友，无法重复申请", user_id, peer_id);
                return err_response_func(request->request_id(), "已经申请过好友，无法重复申请");
            }
            // 4.通过数据库句柄来进行好友申请事件的创建
            FriendApply fa(event_id, user_id, peer_id);
            ret = _mysql_apply->insert(fa);
            if (ret == false)
            {
                LOG_ERROR("好友申请事件[{}]-[{}]创建失败", user_id, peer_id);
                return err_response_func(request->request_id(), "好友申请事件创建失败");
            }
            response->set_notify_event_id(event_id);
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void FriendAddProcess(google::protobuf::RpcController *controller,
                              const ::bite_im::FriendAddProcessReq *request,
                              ::bite_im::FriendAddProcessRsp *response,
                              ::google::protobuf::Closure *done)
        {
            // 场景：当applyer他向user发送FriendAdd请求，然后在客户端中user要进行同意？拒绝？
            // 那么这个时候确认完后，user就要发起FriendAddProcess来进行处理，通过选择来进行相应的操作

            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);

            // 1.提取申请人id、被申请人id，处理结果
            std::string event_id = request->notify_event_id();
            std::string applyer_id = request->apply_user_id(); // 申请人
            std::string user_id = request->user_id();          // 处理是否添加的人
            // 2.判断有没有该申请事件---处理两边都发送申请，如果我向他已经发起了申请，那么在他发起申请后就自动添加了
            bool ret = _mysql_apply->exist(applyer_id, user_id);
            if (ret == false)
            {
                LOG_ERROR("好友申请事件[{}]-[{}]不存在", applyer_id, user_id);
                return err_response_func(request->request_id(), "好友申请事件查询失败");
            }
            // 3.存在就删除这个事件，后续进行处理这个事件
            ret = _mysql_apply->remove(applyer_id, user_id);
            if (ret == false)
            {
                LOG_ERROR("删除好友申请事件[{}]-[{}]失败", applyer_id, user_id);
                return err_response_func(request->request_id(), "好友申请事件删除失败");
            }
            // 4.如果处理结果是拒绝--直接返回，同意继续接下来的逻辑
            if (request->agree() == false)
            {
                // 组织响应
                response->set_request_id(request->request_id());
                response->set_success(false);
                return;
            }
            // 5.在数据库句柄中添加好友关系
            ret = _mysql_relation->insert(user_id, applyer_id);
            if (ret == false)
            {
                LOG_ERROR("添加好友[{}]-[{}]关系失败", applyer_id, user_id);
                return err_response_func(request->request_id(), "添加好友关系失败");
            }
            // 6.在会话模块添加会话信息
            std::string session_id = UUID::uuid(); // 获取会话id
            // 构造session对象，默认单聊的聊天名为空，后续引入用户子服务转化为对方的名称
            ChatSession session(session_id, "", bite_im::ChatSessionType::SINGLE);
            ret = _mysql_session->insert(session);
            if (ret == false)
            {
                LOG_ERROR("新增会话[{}]信息失败", session_id);
                return err_response_func(request->request_id(), "新增会话信息失败");
            }
            // 7.在会话成员模块添加会话成员信息
            ChatSessionMember member1(session_id, user_id);
            ChatSessionMember member2(session_id, applyer_id);
            _mysql_session_member->append(member1);
            if (ret == false)
            {
                LOG_ERROR("新增会话[{}]成员[{}]失败", session_id, user_id);
                return err_response_func(request->request_id(), "新增会话成员失败");
            }
            _mysql_session_member->append(member2);
            if (ret == false)
            {
                LOG_ERROR("新增会话[{}]成员[{}]失败", session_id, applyer_id);
                return err_response_func(request->request_id(), "新增会话成员失败");
            }
            // 8.进行响应
            response->set_request_id(request->request_id());
            response->set_success(true);
            response->set_new_session_id(session_id);
        }
        // 本质上是个用户信息搜索
        void FriendSearch(google::protobuf::RpcController *controller,
                          const ::bite_im::FriendSearchReq *request,
                          ::bite_im::FriendSearchRsp *response,
                          ::google::protobuf::Closure *done)
        {
            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                // 无法登陆不用设置保存code_id
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);

            // 1.提取搜索关键字--手机号、用户id、昵称的一部分
            std::string search_key = request->search_key();
            std::string user_id = request->user_id();
            // 2.通过数据库句柄获得当前用户的好友id列表
            auto friend_id_list = _mysql_relation->friends(user_id);
            friend_id_list.push_back(user_id); // 需要同时过滤自己
            // 3.从es搜索引擎获得用户id列表，过滤当前好友，和自己
            auto user_list = _es_user->search(search_key, friend_id_list);
            // 获取用户id列表，需要去重，防止出现电话即昵称的用户
            std::unordered_set<std::string> user_id_list;
            for (auto user : user_list)
            {
                user_id_list.insert(user.user_id());
            }
            // 3.通过用户子服务获取批量用户信息
            if (user_id_list.size() != 0)
            {
                std::unordered_map<std::string, UserInfo> info_map;
                bool ret = GetUserInfo(request->request_id(), user_id_list, info_map);
                if (ret == false)
                {
                    LOG_ERROR("调用用户子服务失败");
                    return err_response_func(request->request_id(), "调用用户子服务失败");
                }
                // 组织响应
                for (const auto &info_it : info_map)
                {
                    // info.second对应着UserInfo对象
                    auto user_info = response->add_user_info();
                    user_info->CopyFrom(info_it.second);
                }
            }
            response->set_request_id(request->request_id());
            response->set_success(true);
        }
        // 获取申请列表
        void GetPendingFriendEventList(google::protobuf::RpcController *controller,
                                       const ::bite_im::GetPendingFriendEventListReq *request,
                                       ::bite_im::GetPendingFriendEventListRsp *response,
                                       ::google::protobuf::Closure *done)
        {
            // 当某个用户上线时，获取已有的申请列表！！！

            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);
            // 1.获取用户id
            std::string user_id = request->user_id();
            // 2.从数据库句柄中获取申请列表
            auto apply_id_vector = _mysql_apply->friendApplys(user_id);
            // 将vector转为set符合GetUserInfo的参数列表
            std::unordered_set<std::string> apply_id_list;
            for (const auto &apply_id : apply_id_vector)
            {
                apply_id_list.insert(apply_id);
            }
            // 3.通过用户子服务获取申请人的信息
            if (apply_id_list.size() != 0)
            {
                std::unordered_map<std::string, UserInfo> info_map;
                bool ret = GetUserInfo(request->request_id(), apply_id_list, info_map);
                if (ret == false)
                {
                    LOG_ERROR("调用用户子服务失败");
                    return err_response_func(request->request_id(), "调用用户子服务失败");
                }
                // 组织响应
                for (const auto &info_it : info_map)
                {
                    // info.second对应着UserInfo对象
                    auto event_info = response->add_event();
                    event_info->mutable_sender()->CopyFrom(info_it.second);
                }
            }
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void GetChatSessionList(google::protobuf::RpcController *controller,
                                const ::bite_im::GetChatSessionListReq *request,
                                ::bite_im::GetChatSessionListRsp *response,
                                ::google::protobuf::Closure *done)
        {
            // 场景：当用户登录到软件时，会有历史的聊天信息，这个模块就是提取单聊和群聊的聊天信息

            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);
            // 1.获取用户id
            std::string user_id = request->user_id();

            // 2.从数据库中获取所有的单聊会话列表
            auto single_chat_list = _mysql_session->singleChatSession(user_id);
            // 获取所有的好友id--用户子服务来获取用户信息
            std::unordered_set<std::string> friend_id_list;
            for (const auto &single_chat : single_chat_list)
            {
                friend_id_list.insert(single_chat.friend_id);
            }
            // 通过用户子服务获取批量用户信息
            if (friend_id_list.size() != 0)
            {
                std::unordered_map<std::string, UserInfo> info_map;
                bool ret = GetUserInfo(request->request_id(), friend_id_list, info_map);
                if (ret == false)
                {
                    LOG_ERROR("调用用户子服务失败");
                    return err_response_func(request->request_id(), "调用用户子服务失败");
                }

                // 组织单聊会话的响应
                for (const auto &single_chat : single_chat_list)
                {
                    auto chat_session_info = response->add_chat_session_info_list();
                    chat_session_info->set_single_chat_friend_id(single_chat.friend_id);
                    chat_session_info->set_chat_session_id(single_chat.chat_session_id);
                    chat_session_info->set_chat_session_name(info_map[single_chat.friend_id].nickname()); // 单聊的会话名称就是好友名称
                    chat_session_info->set_avatar(info_map[single_chat.friend_id].avatar());              // 单聊的会话头像就是好友头像
                    // 通过消息存储子服务获取单聊的最后一条信息的结构
                    MessageInfo prev_msg;
                    ret = GetRecentMsg(request->request_id(), single_chat.chat_session_id, prev_msg);
                    if (ret == false)
                    {
                        continue;
                    }
                    chat_session_info->mutable_prev_message()->CopyFrom(prev_msg);
                }
            }

            // 3.从数据库中获取所有的群聊会话列表
            auto group_chat_list = _mysql_session->groupChatSession(user_id);
            // 因为群聊的名字和头像是固定的，所以我们直接组织就可以了
            for (const auto &group_chat : group_chat_list)
            {
                auto chat_session_info = response->add_chat_session_info_list();
                chat_session_info->set_chat_session_id(group_chat.chat_session_id);
                chat_session_info->set_chat_session_name(group_chat.chat_session_name); // 单聊的会话名称就是好友名称
                // 通过消息存储子服务获取单聊的最后一条信息的结构
                MessageInfo prev_msg;
                bool ret = GetRecentMsg(request->request_id(), group_chat.chat_session_id, prev_msg);
                if (ret == false)
                {
                    continue;
                }
                chat_session_info->mutable_prev_message()->CopyFrom(prev_msg);
            }
            // 3.组织响应
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void ChatSessionCreate(google::protobuf::RpcController *controller,
                               const ::bite_im::ChatSessionCreateReq *request,
                               ::bite_im::ChatSessionCreateRsp *response,
                               ::google::protobuf::Closure *done)
        {
            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                // 无法登陆不用设置保存code_id
                return;
            };
            // 场景：单聊会话中，我们在创建好友时已经创建，所以该模块特指创建群聊会话，群聊至少有3个人

            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);

            // 1.提取信息
            std::string user_id = request->user_id();                     // 群聊发起人信息
            std::string chat_session_name = request->chat_session_name(); // 群聊名称
            // 2.生成会话
            std::string chat_session_id = UUID::uuid();
            ChatSession session(chat_session_id, chat_session_name, ChatSessionType::GROUP);
            // 3.向数据库中添加会话信息
            bool ret = _mysql_session->insert(session);
            if (ret == false)
            {
                LOG_ERROR("添加群聊会话信息失败");
                return err_response_func(request->request_id(), "添加群聊会话信息失败");
            }
            // 4.向数据库中添加会话成员信息
            std::vector<ChatSessionMember> member_list; // 组织群聊成员
            for (int i = 0; i < request->member_id_list_size(); i++)
            {
                ChatSessionMember csm(chat_session_id, request->member_id_list(i));
                member_list.push_back(csm);
            }
            ret = _mysql_session_member->append(member_list);
            if (ret == false)
            {
                LOG_ERROR("添加群聊会话成员信息失败");
                return err_response_func(request->request_id(), "添加群聊会话成员信息失败");
            }
            //
            response->mutable_chat_session_info()->set_chat_session_name(chat_session_name);
            response->mutable_chat_session_info()->set_chat_session_id(chat_session_id);
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

        void GetChatSessionMember(google::protobuf::RpcController *controller,
                                  const ::bite_im::GetChatSessionMemberReq *request,
                                  ::bite_im::GetChatSessionMemberRsp *response,
                                  ::google::protobuf::Closure *done)
        {
            // 场景：当我们在群聊中，查看所有群成员

            // 错误函数---lambda
            auto err_response_func = [this, response](const std::string &request_id,
                                                      const std::string &errmsg) -> void
            {
                response->set_request_id(request_id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                // 无法登陆不用设置保存code_id
                return;
            };
            // 管理rpc对象
            brpc::ClosureGuard rpc_guard(done);
            // 1.获取会话id
            std::string chat_session_id = request->chat_session_id();
            // 2.通过数据库句柄获取当前群聊会话的所有成员id
            auto member_id_vector = _mysql_session_member->members(chat_session_id);
            std::unordered_set<std::string> member_id_list;
            for (const auto &member_id : member_id_vector)
            {
                member_id_list.insert(member_id);
            }
            // 3.通过用户子服务获得所以成员的信息
            std::unordered_map<std::string, UserInfo> info_map;
            bool ret = GetUserInfo(request->request_id(), member_id_list, info_map);
            if (ret == false)
            {
                LOG_ERROR("调用用户子服务失败");
                return err_response_func(request->request_id(), "调用用户子服务失败");
            }
            // 组织响应
            for (const auto &info_it : info_map)
            {
                // info.second对应着UserInfo对象
                auto member_info = response->add_member_info_list();
                member_info->CopyFrom(info_it.second);
            }
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

    private:
        bool GetRecentMsg(const std::string &request_id, const std::string &chat_session_id, MessageInfo &msg)
        {
            auto channel = _service_manager->choose(_message_service_name);
            if (!channel) // 服务不存在
            {
                LOG_ERROR("消息存储服务[{}]节点未找到", _message_service_name);
                return false;
            }
            MsgStorageService_Stub stub(channel.get());
            GetRecentMsgReq req;
            req.set_request_id(request_id);
            req.set_chat_session_id(chat_session_id);
            req.set_msg_count(1); // 只获取一条

            GetRecentMsgRsp resp;
            brpc::Controller cntl;
            stub.GetRecentMsg(&cntl, &req, &resp, nullptr);
            if (cntl.Failed() == true || resp.success() == false)
            {
                LOG_ERROR("消息存储服务调用失败，原因[{}]", cntl.ErrorText());
                return false;
            }
            // 接收这条消息
            if (resp.msg_list_size() > 0) // 可能是空聊天
            {
                msg.CopyFrom(resp.msg_list(0));
                return true;
            }
            return false;
        }
        bool GetUserInfo(const std::string &request_id, const std::unordered_set<std::string> &user_id_list,
                         std::unordered_map<std::string, UserInfo> &user_info_map)
        {
            auto channel = _service_manager->choose(_user_service_name);
            if (!channel) // 服务不存在
            {
                LOG_ERROR("用户子服务[{}]节点未找到", _user_service_name);
                return false;
            }
            UserService_Stub stub(channel.get());
            GetMultiUserInfoReq req;
            req.set_request_id(request_id);
            for (const auto &user_id : user_id_list)
            {
                req.add_users_id(user_id);
            }
            GetMultiUserInfoRsp resp;
            brpc::Controller cntl;
            stub.GetMultiUserInfo(&cntl, &req, &resp, nullptr);
            if (cntl.Failed() == true || resp.success() == false)
            {
                LOG_ERROR("用户子服务调用失败，原因[{}]", cntl.ErrorText());
                return false;
            }
            // 4.获取GetMultiUserInfo的返回map<std::string, UserInfo>对象
            const auto &info_map = resp.users_info();
            for (const auto &info : info_map)
            {
                user_info_map[info.first] = info.second;
            }
            return true;
        }

    private:
        // es存储
        ESUser::ptr _es_user;
        // mysql存储
        FriendApplyTable::ptr _mysql_apply;                // 好友申请表管理
        RelationTable::ptr _mysql_relation;                // 朋友关系表管理
        ChatSessionTable::ptr _mysql_session;              // 聊天会话表管理
        ChatSessionMemberTable::ptr _mysql_session_member; // 聊天会话成员表管理

        // rpc获取用户子服务、消息存储子服务信道
        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManager::ptr _service_manager;
    };

    class FriendServer
    {
        using RpcServerPtr = std::shared_ptr<brpc::Server>;

    public:
        using ptr = std::shared_ptr<FriendServer>;
        FriendServer(const Discovery::ptr &dis_client,
                     const Registry::ptr &reg_client,
                     const RpcServerPtr &rpc_server,
                     const ElasticPtr &es_client,
                     const DBPtr &mysql_client)
            : _dis_client(dis_client),
              _reg_client(reg_client),
              _rpc_server(rpc_server),
              _es_client(es_client),
              _mysql_client(mysql_client) {}
        ~FriendServer() {}

        // 启动RPC服务器
        void start()
        {
            _rpc_server->RunUntilAskedToQuit();
        }

    private:
        // 项目运行期间都需要持续维护这些对象
        ElasticPtr _es_client;
        DBPtr _mysql_client;

        Discovery::ptr _dis_client;
        Registry::ptr _reg_client;
        RpcServerPtr _rpc_server;
    };

    /*建造者设计模式，封装对象的构造过程，防止用户在进行操作时，对未构造的对象进行操作*/

    class FriendServerBuilder
    {
        using RpcServerPtr = std::shared_ptr<brpc::Server>;

    public:
        void make_mysql_object(const std::string &mysql_user_name,
                               const std::string &mysql_password,
                               const std::string &db_name,
                               const std::string &mysql_host,
                               int mysql_port,
                               const std::string &cset,
                               int conn_pool_num)
        {
            _mysql_client = ODBFactory::create(mysql_user_name, mysql_password, db_name,
                                               mysql_host, mysql_port, cset, conn_pool_num);
        }
        void make_es_object(const std::vector<std::string> &es_host_list)
        {
            _es_client = ElasticFactory::create(es_host_list);
        }
        // 构造服务发现和服务管理客户端
        void make_find_object(const std::string &reg_host,
                              const std::string &base_service_name,
                              const std::string &user_service_name,
                              const std::string &message_service_name)
        {
            _user_service_name = user_service_name;
            _message_service_name = message_service_name;
            _service_manager = std::make_shared<ServiceManager>();
            _service_manager->declareService(_user_service_name);
            _service_manager->declareService(_message_service_name);

            LOG_INFO("在用户服务中添加了用户子服务[{}]", _user_service_name);
            LOG_INFO("在用户服务中添加了消息存储子服务[{}]", _message_service_name);

            auto put_cb = std::bind(&bite_im::ServiceManager::onServiceOnline, _service_manager.get(),
                                    std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&bite_im::ServiceManager::onServiceOffLine, _service_manager.get(),
                                    std::placeholders::_1, std::placeholders::_2);
            _dis_client = std::make_shared<Discovery>(base_service_name, reg_host, put_cb, del_cb);
        }
        // 构造服务注册客户端对象
        void make_reg_object(const std::string &reg_host,
                             const std::string &service_name,
                             const std::string &access_host)
        {
            _reg_client = std::make_shared<Registry>(reg_host);
            _reg_client->registry(service_name, access_host);
        }
        // 搭建rpc服务器
        void make_rpc_server(uint16_t port, int32_t time_out, uint8_t num_threads)
        {
            // 防止未完全构造所需对象
            if (_es_client.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未初始化es客户端模块");
                abort();
            }
            if (_mysql_client.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未初始化mysql客户端模块");
                abort();
            }
            if (_service_manager.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未初始化服务管理模块");
                abort();
            }

            // 创建rpc服务器对象
            _rpc_server = std::make_shared<brpc::Server>();

            // 构建服务，并添加服务
            FriendServiceImpl *service = new FriendServiceImpl(_es_client, _mysql_client, _service_manager,
                                                               _user_service_name, _message_service_name); // 注意这里需要在堆上开辟空间
            int ret = _rpc_server->AddService(service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if (ret == -1)
            {
                LOG_ERROR("rpc服务器添加服务失败");
                abort();
            }

            auto options = std::make_shared<brpc::ServerOptions>();
            // 启动服务器
            options->idle_timeout_sec = time_out; // 连接空闲超时时间
            options->num_threads = num_threads;
            ret = _rpc_server->Start(port, options.get());
            if (ret == -1)
            {
                LOG_ERROR("服务器启动失败");
                abort();
            }
        }

        FriendServer::ptr build()
        {
            // 检测维护对象是否建立
            if (_dis_client.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未初始化服务发现模块");
                abort();
            }
            if (_reg_client.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未初始化服务注册模块");
                abort();
            }
            if (_rpc_server.get() == nullptr)
            {
                LOG_ERROR("服务器建造失败，未搭建Rpc服务器");
                abort();
            }

            FriendServer::ptr server = std::make_shared<FriendServer>(_dis_client, _reg_client, _rpc_server,
                                                                      _es_client, _mysql_client);
            return server;
        }

    private:
        // 数据管理模块
        ElasticPtr _es_client;
        DBPtr _mysql_client;

        // 服务注册和发现模块
        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManager::ptr _service_manager;
        Discovery::ptr _dis_client;
        Registry::ptr _reg_client;
        // rpc服务器
        RpcServerPtr _rpc_server;
    };
}